/*
 * WinampController.java
 *
 * Created on 9 de Outubro de 2007, 14:06
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 * Package containing the Controller Class to communicate with Winamp.
 *
 * @author Francisco Guimar�es
 */
package com.qotsa.jni.controller;

import java.io.File;

import com.qotsa.exception.InvalidHandle;
import com.qotsa.exception.InvalidParameter;

/**
 * This class is a wrapper to call JNI functions to send Message to Winamp
 * Window.
 * 
 * @author Francisco Guimar�es
 * 
 * 
 */
public class WinampController {

	/**
	 * Constant used as return in getTime() Value = -1
	 */
	public static final int ISNOTPLAYING = -1;

	/**
	 * Constant used as parameter in getTime() method Value = 0
	 */
	public static final int CURRENTTIME = 0;

	/**
	 * Constant used as parameter in getTime() method Value = 1
	 */
	public static final int TIMELENGTH = 1;

	/**
	 * Constant used as return in getStatus() method Value = 0
	 */
	public static final int STOPPED = 0;

	/**
	 * Constant used as return in getStatus() method Value = 1
	 */
	public static final int PLAYING = 1;

	/**
	 * Constant used as return in getStatus() method Value = 3
	 */
	public static final int PAUSED = 3;

	/**
	 * Verify if Winamp is started and if not started, starts it.
	 * 
	 * @throws java.lang.Exception
	 *             When the key
	 *             HKEY_LOCAL_MACHINE\Software\Clients\Media\Winamp\
	 *             shell\open\command is not found in the register. This key is
	 *             used to find Winamp Directory installation to execute it.
	 */

	public static void run() throws Exception {

		if (!JNIWinamp.run())
			throw new Exception(
					"Unable to run Winamp. Verify if it is properly installed");

	}

	/**
	 * Exit Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void exit() throws InvalidHandle {

		if (!JNIWinamp.exit())
			throw new InvalidHandle();

	}

	/**
	 * Play current file in Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void play() throws InvalidHandle {

		if (!JNIWinamp.play())
			throw new InvalidHandle();

	}

	/**
	 * Stop current file in Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void stop() throws InvalidHandle {

		if (!JNIWinamp.stop())
			throw new InvalidHandle();

	}

	/**
	 * Resume current file in Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void resume() throws InvalidHandle {

		if (!JNIWinamp.resume())
			throw new InvalidHandle();

	}

	/**
	 * Pause Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void pause() throws InvalidHandle {

		if (!JNIWinamp.pause())
			throw new InvalidHandle();

	}

	/**
	 * 
	 * Go to Previous Track in the play list.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void previousTrack() throws InvalidHandle {

		if (!JNIWinamp.previousTrack())
			throw new InvalidHandle();

	}

	/**
	 * Go to Next Track in the play list.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void nextTrack() throws InvalidHandle {

		if (!JNIWinamp.nextTrack())
			throw new InvalidHandle();

	}

	/**
	 * Fowards 5 seconds on the current song.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void fwd5Secs() throws InvalidHandle {

		if (!JNIWinamp.fwd5Secs())
			throw new InvalidHandle();

	}

	/**
	 * Rewinds 5 seconds on the current song.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void rew5Secs() throws InvalidHandle {

		if (!JNIWinamp.rew5Secs())
			throw new InvalidHandle();

	}

	/**
	 * Increase Volume a little bit.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void increaseVolume() throws InvalidHandle {

		if (!JNIWinamp.increaseVolume())
			throw new InvalidHandle();

	}

	/**
	 * Decrease Volume a little bit.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void decreaseVolume() throws InvalidHandle {

		if (!JNIWinamp.decreaseVolume())
			throw new InvalidHandle();

	}

	/**
	 * Increase Volume.
	 * 
	 * @param percent
	 *            Percent to Increase Volume.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If percent not between 0 and 100
	 */
	public static void increaseVolumePercent(int percent) throws InvalidHandle,
			InvalidParameter {

		if ((percent < 0) || (percent > 100))
			throw new InvalidParameter(
					"percent�s value must be between 0 and 100");

		if (!JNIWinamp.increaseVolumePercent(percent))
			throw new InvalidHandle();

	}

	/**
	 * Decrease Volume.
	 * 
	 * @param percent
	 *            Percent to Decrease Volume.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If percent not between 0 and 100
	 */
	public static void decreaseVolumePercent(int percent) throws InvalidHandle,
			InvalidParameter {

		if ((percent < 0) || (percent > 100))
			throw new InvalidParameter(
					"percent�s value must be between 0 and 100");
		if (!JNIWinamp.decreaseVolumePercent(percent))
			throw new InvalidHandle();

	}

	/**
	 * Adjust Volume. Note that the pos must be between 0(0%) and 255 (100%).
	 * 
	 * @param pos
	 *            Position to Set Volume.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If pos not between 0 and 255
	 */
	public static void setVolume(int pos) throws InvalidHandle,
			InvalidParameter {

		if ((pos < 0) || (pos > 255))
			throw new InvalidParameter("pos value must be between 0 and 255");
		if (!JNIWinamp.setVolume(pos))
			throw new InvalidHandle();

	}

	/**
	 * Restarts Winamp.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws java.lang.Exception
	 *             When failed to restart Winamp.
	 */
	public static void restart() throws InvalidHandle, Exception {

		exit();
		run();

	}

	/**
	 * Go to a Specified Position in the List. This method doesn�t play. Just
	 * set list position. If you wanna play call play() after set position.
	 * Parameter pos is Zero-based index.
	 * 
	 * @param pos
	 *            Position.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If pos is negative or greater than List Length.
	 */
	public static void setPlaylistPosition(int pos) throws InvalidHandle,
			InvalidParameter {

		int listLength = getPlayListLength();
		if ((pos < 0) || ((pos + 1) > listLength))
			throw new InvalidParameter("Position is invalid in the list.");
		if (!JNIWinamp.setPlaylistPosition(pos))
			throw new InvalidHandle();

	}

	/**
	 * Clear Winamp's internal playlist.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void clearPlayList() throws InvalidHandle {

		if (!JNIWinamp.clearPlayList())
			throw new InvalidHandle();

	}

	/**
	 * Flush the playlist cache buffer. Call this if you want it to go refetch
	 * titles for tracks in the list.
	 * 
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void refreshPlayListCache() throws InvalidHandle {

		if (!JNIWinamp.refreshPlayListCache())
			throw new InvalidHandle();

	}

	/**
	 * Return the PlayListLength.
	 * 
	 * @return List Length.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static int getPlayListLength() throws InvalidHandle {

		int length = JNIWinamp.getPlayListLength();
		if (length == -1)
			throw new InvalidHandle();
		return length;

	}

	/**
	 * Write a Playlist in winampDirInstallation\\Winamp.m3u. This is default
	 * Winamp IPC Default. If you wanna change this, just rename the file you�ve
	 * created.
	 * 
	 * @return Current List Position.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static int writePlayListToFile() throws InvalidHandle {

		int playListPos = JNIWinamp.writePlayListToFile();
		if (playListPos == -1)
			throw new InvalidHandle();
		return playListPos;

	}

	/**
	 * Verify if Shuffle is On.
	 * 
	 * @return True - On ; False - Off.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static boolean isShuffleStatusOn() throws InvalidHandle {

		int status = JNIWinamp.isShuffleStatusOn();
		if (status == -1)
			throw new InvalidHandle();
		return (status == 1 ? true : false);

	}

	/**
	 * Verify if Repeat is On.
	 * 
	 * @return True - On ; False - Off.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static boolean isRepeatStatusOn() throws InvalidHandle {

		int status = JNIWinamp.isRepeatStatusOn();
		if (status == -1)
			throw new InvalidHandle();
		return (status == 1 ? true : false);

	}

	/**
	 * Turn on Repeat.
	 * 
	 * @param mode
	 *            True - Turn on Repeat ; False - Turn off Repeat.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void setRepeatStatusOn(boolean mode) throws InvalidHandle {

		if (!JNIWinamp.setRepeatStatusOn(mode))
			throw new InvalidHandle();

	}

	/**
	 * Turn on Shuffle.
	 * 
	 * @param mode
	 *            True - Turn on Shuffle ; False - Turn off Shuffle.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static void setShuffleStatusOn(boolean mode) throws InvalidHandle {

		if (!JNIWinamp.setShuffleStatusOn(mode))
			throw new InvalidHandle();

	}

	/**
	 * Append a File into the List.
	 * 
	 * @param filename
	 *            FileName to Append in the list.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If the filename is an invalid path.
	 */
	public static void appendToPlayList(String filename) throws InvalidHandle,
			InvalidParameter {

		File file = new File(filename);
		if (!file.exists())
			throw new InvalidParameter("File doesn�t exists.");
		if (!JNIWinamp.appendToPlayList(filename))
			throw new InvalidHandle();

	}

	/**
	 * Get Winamp Status.
	 * 
	 * @return STOPPED - Stop PLAYING - play PAUSED - Paused
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static int getStatus() throws InvalidHandle {

		int status = JNIWinamp.getStatus();
		if (status == -1)
			throw new InvalidHandle();
		return status;

	}

	/**
	 * Get Current List Pos.
	 * 
	 * @return Current List Position.
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static int getListPos() throws InvalidHandle {

		int pos = JNIWinamp.getListPos();
		if (pos == -1)
			throw new InvalidHandle();
		return pos;

	}

	/**
	 * Get Current Track Title.
	 * 
	 * @return Current Track Title
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 */
	public static String getTitle() throws InvalidHandle {

		String title = JNIWinamp.getTitle();
		if (title == null)
			throw new InvalidHandle();
		return title;

	}

	/**
	 * Get Current Track FileName. Parameter pos is Zero-based index.
	 * 
	 * @return Current Track FileName
	 * @param pos
	 *            Track Position in the Current PlayList
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             If pos is negative or greater than List Length
	 */
	public static String getFileNameInList(int pos) throws InvalidHandle,
			InvalidParameter {

		int listLength = getPlayListLength();
		if ((pos < 0) || (pos > listLength))
			throw new InvalidParameter("Position is invalid in the list.");
		String filename = JNIWinamp.getFileNameInList(pos);
		if (filename == null)
			throw new InvalidHandle();
		return filename;

	}

	/**
	 * Get Song Time.
	 * 
	 * @return Time Song (depends on Param mode) or ISNOTPLAYING if there is no
	 *         info about time because it not starts to play.
	 * @param mode
	 *            CURRENTTIME - Currently Time in Milliseconds TIMELENGHT - Song
	 *            Time Length in seconds
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             if parameter is not CURRENTTIME or TIMELENGTH.
	 */
	public static int getTime(int mode) throws InvalidHandle, InvalidParameter {

		if (mode != CURRENTTIME && mode != TIMELENGTH)
			throw new InvalidParameter();
		int time = JNIWinamp.getTime(mode);
		if (time == -2)
			throw new InvalidHandle();
		return time;

	}

	/**
	 * Fowards n Tracks in Play List.
	 * 
	 * @param n
	 *            Number of Tracks to Foward
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             if n is negative or Zero.
	 */
	public static void fwdTracks(int n) throws InvalidParameter, InvalidHandle {

		if (n <= 0)
			throw new InvalidParameter("Value must be Positive");
		int pos = getListPos();
		int lengthList = getPlayListLength();
		int newPos = pos + n;
		if (newPos > lengthList) {
			setPlaylistPosition(lengthList);
			play();
		} else {
			setPlaylistPosition(newPos);
			play();
		}

	}

	/**
	 * Rewinds n Tracks in Play List.
	 * 
	 * @param n
	 *            Number of Tracks to Rewind
	 * @throws com.qotsa.exception.InvalidHandle
	 *             When the Winamp Windows is not handle(in most case, it means
	 *             that winamp is not running)
	 * @throws com.qotsa.exception.InvalidParameter
	 *             if n is negative or Zero.
	 */
	public static void rewTracks(int n) throws InvalidParameter, InvalidHandle {

		if (n <= 0)
			throw new InvalidParameter("Value must be Positive");
		int pos = getListPos();
		int newPos = pos - n;
		if (newPos < 0) {
			setPlaylistPosition(0);
			play();
		} else {
			setPlaylistPosition(newPos);
			play();
		}

	}

	/**
	 * Get File Name Playing In Winamp.
	 * 
	 * @return Current File Name.
	 */
	public static String getFileNamePlaying() throws InvalidHandle {

		String fileName = JNIWinamp.getFileNamePlaying();
		if (fileName == null)
			throw new InvalidHandle();
		return fileName;

	}

}